/*
	A hash table implementation to contain pointers to PCBs.
*/

#include <pm.h>

int initialized = 0;
void init_process_table(){
	if(initialized) return;
	initialized = 1;
	int i = 0;
	for(; i < N_PROC_BUCKETS; i++) 
		procs_hash_table[i] = 0;
	for(i = 0; i < MAX_PROCS; i++)
		procs[i].valid = 0;
}

inline int pid_to_hash(int pid, int buckets);

/*
 * Puts the process into the hash table. Also checks whether there is another
 * process already stored with the same pid. If so, returns -1. Else, stores
 * the process and returns 0. Returns -2 if the input process is NULL (?!).
 */
int put_process(struct process *p){
	if(p == 0) return -2;
	int hash = pid_to_hash(p->pid,N_PROC_BUCKETS),
			pid = p->pid;
	
	struct process *prev = procs_hash_table[hash];
	if(prev == 0){
		// New process will be the first element in its bucket.
		procs_hash_table[hash] = p;
		return 0;
	} else {
		while(prev->next_hash_p != 0){
			if(prev->pid == pid)
				return -1;
			prev = prev->next_hash_p;
		}
		if(prev->pid == pid)
			return -1;
		prev->next_hash_p = p;
		// We just put it here; it should not have a next_hash_p.
		p->next_hash_p = 0;
		return 0;
	}
}

/* 
 * Finds and returns the process by its ID in the procs_hash_table hash table. 
 * Returns NULL if the specified pid is not found. 
 * Defined in pm.h
 */
inline struct process* get_process_by_pid(int pid){
	struct process *p = procs_hash_table[pid_to_hash(pid,N_PROC_BUCKETS)];
	while(p != 0 && p->pid != pid)
		p = p->next_hash_p;
	return p;
}

/*
 * This function gets the pid of the process because it needs to search
 * in the table to  find its previous bucket sibling anyway. Returns a
 * pointer to the PCB of the process if found (after removing), NULL otherwise.
 * This method is meant to be called after a process terminates.
 */
struct process* remove_process(int pid){
	int hash = pid_to_hash(pid,N_PROC_BUCKETS);
	struct process *p = procs_hash_table[hash],
	               *prev = 0;
	while(p != 0 && p->pid != pid){
		prev = p;
		p = p->next_hash_p;
	}
	if(p != 0){
		if(prev != 0)
			prev->next_hash_p = p->next_hash_p;
		else
			procs_hash_table[hash] = p->next_hash_p;
	}
	return p;
}


/* 
 * This is very very very simple implementation for the time being. 
 * It will be improved if it causes any problems for our purposes.
 */
inline int pid_to_hash(int pid, int buckets){
	return pid % buckets;
}


